package com.clei.Y2020.M07.D23;

import com.clei.utils.PrintUtil;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 好久没写socket程序了，试一哈
 *
 * @author KIyA
 */
public class TCPSocketServer {

    public static void main(String[] args) throws Exception {

        ServerSocket serverSocket = new ServerSocket(8001);
        // 最多允许三个客户端同时在线
        int clientLimit = 3;
        AtomicInteger counter = new AtomicInteger();
        ExecutorService executor = Executors.newFixedThreadPool(clientLimit);

        PrintUtil.log("begin");
        while (true) {
            Socket socket = serverSocket.accept();
            if (counter.get() == clientLimit) {
                byte[] closeMsg = "close".getBytes();
                socket.getOutputStream().write(closeMsg, 0, closeMsg.length);
                socket.close();
                PrintUtil.log("close");
            } else {
                byte[] connectMsg = "connect".getBytes();
                socket.getOutputStream().write(connectMsg, 0, connectMsg.length);
                counter.incrementAndGet();
                PrintUtil.log("connect");
                executor.execute(() -> {
                    byte[] buffer = new byte[1024];
                    while (true) {
                        boolean close = readAndWrite(socket, buffer);
                        if (close) {
                            counter.decrementAndGet();
                            break;
                        }
                    }
                    try {
                        socket.close();
                    } catch (Exception e) {
                        PrintUtil.log("socket close error ", e);
                    }
                });
            }
        }
    }

    /**
     * 读取并回复
     *
     * @param socket Socket
     * @param buffer buffer
     * @return 是否关闭
     */
    private static boolean readAndWrite(Socket socket, byte[] buffer) {
        try {
            // 读取
            InputStream is = socket.getInputStream();
            int length = is.read(buffer);
            if (-1 == length) {
                is.close();
                return true;
            }
            String content = new String(buffer, 0, length, StandardCharsets.UTF_8);
            PrintUtil.log(content);
            // 写入
            OutputStream os = socket.getOutputStream();
            os.write(buffer, 0, length);

            if ("EXIT".equalsIgnoreCase(content)) {
                os.close();
                is.close();
                return true;
            }
        } catch (Exception e) {
            return true;
        }
        return false;
    }
}
